var Turret = require('js/turret').Turret;
var Projectile = require('js/turrets/projectile').Projectile;
var Match = require('js/match').Match;
var Map = require('js/map').Map;
var Enemy = require('js/enemy').Enemy;
var gamejs = require('gamejs');

qModule('js/turret', {
	setup: function() {
		this.match = new Match();
		this.map = new Map(this.match, 800, 400);
		this.match.setMap(this.map);
		this.match.start();
		this.turret_center = [100, 100];
		this.turret = new Turret(this.match, this.turret_center);
	}
});

test("Turret(match, coordinates, tf)", function() {
	ok(this.turret instanceof Turret,
		"Test with arguments (Match, [Number, Number], default): " +
		"object correctly created."
	);
	deepEqual(this.turret.getMatch(), this.match,
		"Test with arguments (Match, [Number, Number], default): " +
		"match correctly setted."
	);
	deepEqual(this.turret.getCenter(), this.turret_center,
		"Test with arguments (Match, [Number, Number], default): " +
		"center correctly setted."
	);
	var nearest = Turret.TARGETTING_FUNCTIONS.nearest;
	deepEqual(this.turret.getTargettingFunction(), nearest,
		"Test with arguments (Match, [Number, Number], default): " +
		"default tf correctly setted."
	);
	// Test constructor with another targetting function
	var strongest = Turret.TARGETTING_FUNCTIONS.strongest;
	var strongTurret = new Turret(this.match, this.turret_center, strongest);
	deepEqual(strongTurret.getTargettingFunction(), strongest,
		"Test with arguments (Match, [Number, Number], strongest): " +
		"tf correctly setted."
	);
});

test("Turret.getCenter()", function() {
	deepEqual(this.turret.getCenter(), this.turret_center, "Works!");
});

test("Turret.getTargettingFunction()", function() {
	var defaultTargetting = Turret.TARGETTING_FUNCTIONS.nearest;
	deepEqual(this.turret.getTargettingFunction(), defaultTargetting,
		"Works!"
	);
});

test("Turret.setTargettingFunction(targettingFunction)", function() {
	var weakest = Turret.TARGETTING_FUNCTIONS.weakest;
	this.turret.setTargettingFunction(weakest);
	deepEqual(this.turret.getTargettingFunction(), weakest,
		"Test with argument (Turret.TARGETTING_FUNCTIONS.weakest)."
	);
	var strongest = Turret.TARGETTING_FUNCTIONS.strongest;
	this.turret.setTargettingFunction(strongest);
	deepEqual(this.turret.getTargettingFunction(), strongest,
		"Test with argument (Turret.TARGETTING_FUNCTIONS.strongest)."
	);
});

test("Turret.getRange()", function() {
	// this.turret starts as a base level turret
	deepEqual(this.turret.getRange(), Turret.UPGRADE_LIST[0].range,
		"Test on a level 0 Turret."
	);
	// level 1 turret
	this.turret.upgrade();
	deepEqual(this.turret.getRange(), Turret.UPGRADE_LIST[1].range,
		"Test on a level 1 Turret."
	);
});

test("Turret.getReloadTime()", function() {
	// this.turret starts as a base level turret
	deepEqual(this.turret.getReloadTime(), Turret.UPGRADE_LIST[0].reloadTime,
		"Test on a level 0 Turret."
	);
	// level 1 turret
	this.turret.upgrade();
	deepEqual(this.turret.getReloadTime(), Turret.UPGRADE_LIST[1].reloadTime,
		"Test on a level 1 Turret."
	);
});

test("Turret.getProjectilePower()", function() {
	// this.turret starts as a base level turret
	var power = Turret.UPGRADE_LIST[0].projectilePower;
	deepEqual(this.turret.getProjectilePower(), power,
		"Test on a level 0 Turret."
	);
	// level 1 turret
	this.turret.upgrade();
	power = Turret.UPGRADE_LIST[1].projectilePower;
	deepEqual(this.turret.getProjectilePower(), power,
		"Test on a level 1 Turret."
	);
});

test("Turret.getMatch()", function() {
	deepEqual(this.turret.getMatch(), this.match, "Works!");
});

test("Turret.upgrade()", function() {
	this.turret.upgrade();
	deepEqual(this.turret.getLevel(), 1,
		"Test with upgrade from level 0 to 1"
	);
});

test("Turret.getWeaponCoordinates()", function() {
	var wCoordinates = this.turret._weaponCoordinates;
	deepEqual(this.turret.getWeaponCoordinates(), wCoordinates, "Works!");
});

test("Turret._targetEnemy()", function() {
	// Define some enemies
	var inRangeCenterNearPlanet = [
		/*this.turret_center[0] - this.turret.getRange() + */ //error due negative coordinates
		20,
		this.turret_center[1]
	];
	var inRangeCenterFarPlanet = [
		this.turret_center[0] + this.turret.getRange() - 20,
		this.turret_center[1]
	];
	var outOfRangeCenter = [
		this.turret_center[0] + this.turret.getRange() + 20,
		this.turret_center[1]
	];
	var enemy1 = new Enemy(this.match, inRangeCenterNearPlanet, 0, 1);
	enemy1.health = 100;
	var enemy2 = new Enemy(this.match, inRangeCenterFarPlanet, 0, 1);
	var enemy3 = new Enemy(this.match, outOfRangeCenter, 0 ,1);
	this.turret.getMatchMap().addGameEntity(enemy1);
	this.turret.getMatchMap().addGameEntity(enemy2);
	this.turret.getMatchMap().addGameEntity(enemy3);
	// Test with enemies invisibles
	equal(this.turret._targetEnemy(), null,
		"Test with invisible enemies."
	);
	// Test with one visible enemy but out of range
	enemy3.setDetected(true);
	equal(this.turret._targetEnemy(), null,
		"Test with one visible enemy but out of range."
	);
	// Test with an enemy visibile and in range
	enemy1.setDetected(true);
	equal(this.turret._targetEnemy(), enemy1,
		"Test with one visible and in-range enemy."
	);
	// Tests with two visible and in range enemies
	// Target the one nearer the planet
	enemy2.setDetected(true);
	equal(this.turret._targetEnemy(), enemy1,
		"Test with two visible and in range enemies: " +
		"target the one nearer the planet."
	);
	// Target the one with more hp
	this.turret.targettingFunction = Turret.TARGETTING_FUNCTIONS.strongest;
	equal(this.turret._targetEnemy(), enemy1,
		"Test with two visible and in range enemies: " +
		"target the one with more hp."
	);
	// Target the one with less hp
	this.turret.targettingFunction = Turret.TARGETTING_FUNCTIONS.weakest;
	equal(this.turret._targetEnemy(), enemy2,
		"Test with two visible and in range enemies: " +
		"target the one with less hp."
	);
});

test("Turret._checkRangeEnemy()", function() {
	// Test on a enemy in range
	var range = this.turret.getRange();
	var inRangeEnemyCenter = [
		this.turret_center[0] + range - 20,
		this.turret_center[1]
	];
	var inRangeEnemy = new Enemy(this.match, inRangeEnemyCenter, 0, 1);
	ok(this.turret._checkRangeEnemy(inRangeEnemy),
		"Test on a enemy inside Turret Range."
	);
	// Test on a enemy outside firing range
	var outOfRangeEnemyCenter = [
		this.turret_center[0] + range + 20,
		this.turret_center[1]
	];
	var outOfRangeEnemy = new Enemy(this.match, outOfRangeEnemyCenter, 0, 1);
	ok(! this.turret._checkRangeEnemy(outOfRangeEnemy),
		"Test on a enemy inside Turret Range."
	);
	// Test on a dummy enemy on the range border
	var dummyEnemyCenter = [
		this.turret_center[0],
		this.turret_center[1] + range
	];
	var dummyEnemy = {
		rect: new gamejs.Rect(dummyEnemyCenter)
	};
	ok(this.turret._checkRangeEnemy(dummyEnemy),
		"Test on a dummy enemy on range border."
	);
	// Test on a dummy enemy just inside range borders
	dummyEnemyCenter = [
		this.turret_center[0],
		this.turret_center[1] + range - 1
	];
	dummyEnemy.rect = new gamejs.Rect(dummyEnemyCenter);
	ok(this.turret._checkRangeEnemy(dummyEnemy),
		"Test on a dummy enemy just inside range."
	);
	// Test on a dummy enemy just outside range borders
	dummyEnemyCenter = [
		this.turret_center[0],
		this.turret_center[1] + range + 1
	];
	dummyEnemy.rect = new gamejs.Rect(dummyEnemyCenter);
	ok(! this.turret._checkRangeEnemy(dummyEnemy),
		"Test on a dummy enemy just outside range."
	);
});

test("Turret.TARGETTING_FUNCTIONS.nearest(enemy1, enemy2)", function() {
	var enemy1 = new Enemy(this.match, [20,100], 0);
	var enemy2 = new Enemy(this.match, [100,100], 0);
	var enemy3 = new Enemy(this.match, [400,100], 0);
	var enemy4 = new Enemy(this.match, [400,100], 0);
	// Test with the first enemy nearer the planel
	deepEqual(Turret.TARGETTING_FUNCTIONS.nearest(enemy1, enemy2), enemy1,
		"Test with arguments (Enemy1, Enemy2): Enemy1 nearer the planet."
	);
	// Test with the second enemy nearer the planel
	deepEqual(Turret.TARGETTING_FUNCTIONS.nearest(enemy2, enemy3), enemy2,
		"Test with arguments (Enemy1, Enemy2): Enemy2 nearer the planet."
	);
	// Test with two enemies at the same distance
	deepEqual(Turret.TARGETTING_FUNCTIONS.nearest(enemy3, enemy4), enemy3,
		"Test with arguments (Enemy1, Enemy2): Enemy1 and Enemy2 at the " +
		"same distance."
	);
});

test("Turret.TARGETTING_FUNCTIONS.strongest(enemy1, enemy2)", function() {
	var enemy1 = new Enemy(this.match, [100,100], 0);
	enemy1.health = 100;
	var enemy2 = new Enemy(this.match, [100,100], 0);
	enemy2.health = 50;
	var enemy3 = new Enemy(this.match, [100,100], 0);
	enemy3.health = 25;
	var enemy4 = new Enemy(this.match, [100,100], 0);
	enemy4.health = 25;
	// Test with the first enemy stronger
	deepEqual(Turret.TARGETTING_FUNCTIONS.strongest(enemy1, enemy2), enemy1,
		"Test with arguments (Enemy1, Enemy2): Enemy1 with more hp."
	);
	// Test with the second enemy stronger
	deepEqual(Turret.TARGETTING_FUNCTIONS.strongest(enemy2, enemy3), enemy2,
		"Test with arguments (Enemy1, Enemy2): Enemy2 with more hp."
	);
	// Test with two enemies with the same amount of hp
	deepEqual(Turret.TARGETTING_FUNCTIONS.strongest(enemy3, enemy4), enemy3,
		"Test with arguments (Enemy1, Enemy2): Enemy1 and Enemy2 with the " +
		"same amount of hp."
	);
});

test("Turret.TARGETTING_FUNCTIONS.weakest(enemy1, enemy2)", function() {
	var enemy1 = new Enemy(this.match, [100,100], 0);
	enemy1.health = 25;
	var enemy2 = new Enemy(this.match, [100,100], 0);
	enemy2.health = 50;
	var enemy3 = new Enemy(this.match, [100,100], 0);
	enemy3.health = 100;
	var enemy4 = new Enemy(this.match, [100,100], 0);
	enemy4.health = 100;
	// Test with the first enemy stronger
	deepEqual(Turret.TARGETTING_FUNCTIONS.weakest(enemy1, enemy2), enemy1,
		"Test with arguments (Enemy1, Enemy2): Enemy1 with less hp."
	);
	// Test with the second enemy stronger
	deepEqual(Turret.TARGETTING_FUNCTIONS.weakest(enemy2, enemy3), enemy2,
		"Test with arguments (Enemy1, Enemy2): Enemy2 with less hp."
	);
	// Test with two enemies with the same amount of hp
	deepEqual(Turret.TARGETTING_FUNCTIONS.weakest(enemy3, enemy4), enemy3,
		"Test with arguments (Enemy1, Enemy2): Enemy1 and Enemy2 with the " +
		"same amount of hp."
	);
});